llama.cpp runtime; neither is built in. OAuth-token storage is mixed and depends on vault state, while your twin profile, preferences, memory, receipts, and search indexes remain unencrypted by SkyTwin. Enable full-disk encryption and see How we store and protect your data and Data sharing & transfers for the exact boundaries.
SkyTwin is developed by Jay Zalowitz, an independent open-source contributor. Source code, including the entirety of the data-handling implementation, lives at github.com/jayzalowitz/skytwin under the Apache 2.0 license. There is no SkyTwin Inc., no cloud product, and no centralized data store. Contact: open an issue at github.com/jayzalowitz/skytwin/issues.
The isolated sample does not access Google user data. The current alpha serves the Connect Gmail wizard in the desktop window for first-account setup; an already authenticated local-browser session can use the same page, while a fresh browser cannot inherit the desktop session. You create and supply a Web Application OAuth client in your own Google Cloud project. The historical v0.6.58.0 alpha also had a bundled identity/Calendar client, but that is not a current support or verification claim.
The live path requests identity (openid, email, profile), Calendar (calendar.readonly, calendar.events), and—when Gmail is explicitly selected with a user- or operator-supplied client—gmail.readonly and gmail.modify. Google's calendar.events grant permits viewing and editing events on accessible calendars; gmail.modify permits reading, composing, and sending mail as well as changing mailbox state. Those are maximum grant authorities, not this release's supported behavior. SkyTwin's current capability claim is live Gmail ingestion, Calendar context, token refresh, connector health, and proposals; it does not include supported Gmail send/archive or Calendar mutation.
BYO and managed flows remain subject to Google's current publishing, warning, tester, token-expiry, user-data, verification, and security-assessment requirements. Testing-mode grants involving these scopes expire after seven days. A personal OAuth connection is not evidence that Google approved a SkyTwin-managed client. See the setup guide.
The source tree also contains a BYO Microsoft Graph connection, but real-account setup is outside the supported sample-only preview. It remains disabled unless a source-development deployment uses the same exact experimental account opt-in as Google. If explicitly configured in that unsupported mode, its requested Graph scopes are:
User.Read — to read the signed-in account's basic profile and email address, used as the account key for the local twin profile.Mail.Read — read-only access to Outlook mail so SkyTwin can interpret the same kinds of signals it reads from Gmail.Calendars.Read — read-only access to your Outlook calendar for conflict detection and scheduling context.offline_access — Microsoft's mechanism for issuing a refresh token so background sync survives a restart. It grants no additional data access of its own.The Outlook integration is read-only: SkyTwin does not request write scopes for Microsoft mail or calendar, so it cannot send Outlook mail or modify Outlook events. Any Microsoft user data retained from earlier development work receives the same local storage, encryption, and deletion protections described below; provider-side grant management remains specific to Microsoft.
When you explicitly enable a live Google connection, SkyTwin's permitted use is limited to the user-facing personal-assistant features disclosed at consent time:
SkyTwin does not use Google user data for advertising, model training across users, lending decisions, or any purpose other than the disclosed personal-assistant features. The isolated sample uses no Google user data; the BYO alpha/experimental modes do.
The supported sample uses fictional data. When the desktop alpha or explicitly experimental source mode stores provider data, SkyTwin's persistent copy — including derived signals, decisions, preferences, and twin profile records — is stored in a CockroachDB database on the device where SkyTwin is installed. Providers and any hosted model endpoint you explicitly configure process transmitted data under their own terms; SkyTwin does not mirror this database to a developer-operated service. The local database files live in your operating-system-standard application data directory:
~/Library/Application Support/SkyTwin/crdb-data/%LOCALAPPDATA%\SkyTwin\crdb-data\~/.local/share/SkyTwin/crdb-data/Those files are protected by your operating system's normal file permissions — the same protection as the rest of your home directory. There is no additional SkyTwin-managed encryption layer over them by default.
Supported beta topology: one non-demo human owner per installation. Service credentials and dynamically discovered credential requirements are installation-wide configuration, not separate per-user records. Do not use this beta as a local multi-owner or hosted service.
If an assistant send ends without a definite result, the dashboard temporarily keeps the full pending message and its retry UUID in renderer localStorage; the mobile development client keeps the same recovery record in the operating system secure store. This prevents a reload or app restart from creating a second action for the same logical request. The record is removed after a definite completion or failure, when you edit or explicitly abandon the message, and when you sign out or disconnect. The packaged sample uses tab-scoped sessionStorage and removes the record on sample exit.
dm-crypt on Linux. That is what actually protects your SkyTwin database if your machine is lost or stolen or its disk is imaged. We recommend enabling it before you connect an account.
SkyTwin ships a credential vault (@skytwin/credential-vault) that encrypts stored OAuth access and refresh tokens with AES-256-GCM, using a per-user key derived from a passphrase via scrypt. The key is derived on your device and never leaves it. We would rather be precise than reassuring about what this covers today:
v0.6.58.0 callback had the same plaintext boundary.Your learned preferences (the preferences table), your twin profile (the twin_profiles table — inferences, communication style, risk tolerance, spend norms, routines, domain heuristics), and the textual memory the twin extracts from your correspondence (the brain_pages table — titles, body content, and metadata) are currently stored unencrypted in your local CockroachDB. The same is true of the derived search fields computed from them: the full-text index (content_tsv) and the semantic vector (embedding).
A column-level encryption schema and helpers for those three tables exist in the repository (migration 066-encrypt-high-value-tables.sql and packages/db/src/lib/vault-helper.ts), but they are not yet activated by any shipping code path — no running process supplies the vault key to them, so they operate in plaintext mode. Switching them on is tracked as issue #374. This page will be updated when that ships. Until then, treat those tables as readable by anyone who can read the files on your machine, and rely on full-disk encryption.
Migrations 074-inference-receipts.sql through 079-inference-receipt-capture-order.sql add signed, structured inference receipts and atomic completion authority. A successfully finalized decision-event attempt creates a receipt for each completed model call and atomically persists the complete batch before approval or external execution; a zero-call attempt still records completion. If an existing decision lacks that completion marker, re-ingestion returns recovery-required before client construction, inference, memory writes, receipt admission, approval, or execution. It does not combine partial causative history across attempts; availability-preserving recovery requires a future durable provisional trace journal or atomic-restart design. Each local, unencrypted row can identify the user, decision, explanation, provider, model, endpoint, canonical logical request and provider-neutral response hashes, cost and optional billing identity, verification or fallback status, durable capture-completion order, timestamps, and public signatures. The schema has no dedicated prompt or response fields, and code must not put source content or secrets into its free-form strings; because the contract cannot identify sensitive content inside an arbitrary string, the local encryption inventory conservatively treats the receipt JSON as potentially source-bearing. The authenticated decision receipt GET route reads the latest row and DELETE removes the full batch; deleting the linked decision or user also deletes the batch by database cascade. A separate verification bundle would contain the canonical logical request and provider-neutral response bytes, but this build has no product route or UI that creates such a bundle. See the inference receipt contract and current limitations.
SkyTwin runs no analytics and collects no usage telemetry. The developers do not receive a copy of your application database or dedicated message, calendar, memory, or twin-profile fields. Networked features have narrower disclosures below: prompts go to a cloud AI provider only when you configure one, and the optional crash reporter can send scrubbed error text to a SkyTwin-operated endpoint.
The desktop app includes one optional, default-off diagnostic: “Send anonymous crash reports” in Settings. When — and only when — you turn it on, an unhandled crash uploads a small JSON report to https://crash.skytwin.dev/api/desktop/report containing the exception type, the error message, the stack trace, the app version, and your OS platform and CPU architecture. The message and stack are scrubbed before upload (redactPii in apps/desktop/src/crash-reporter.ts) to remove email addresses, home-directory paths, Bearer credentials, api_key= / token= / secret= / password= values, and bare keys carrying a recognizable vendor prefix (sk-, ghp_, xoxb-, AIza, and similar). The report schema has no account identifier or dedicated signal, memory, message, calendar, or twin-profile field. However, error messages and stacks originate in running application code, and pattern-based scrubbing cannot guarantee that incidental user content or a secret in an unrecognized format is removed. That residual risk is why the setting is off by default. Leaving the setting off means no crash report is ever sent.
SkyTwin does not transfer Google user data to any third party for the developers' benefit — there is no analytics, advertising, model-training, or data-broker pipeline. Features you configure can send selected data over the network through the paths below:
gmail.googleapis.com, calendar.googleapis.com, and graph.microsoft.com) to fetch authorized data. The isolated sample makes no account connector calls; the BYO alpha and explicitly experimental source modes can. A complete provider-mutation runtime is outside the current capability claim.llama.cpp runtime. Builds from current source can download the pinned managed model only after explicit user action; a compatible runtime remains separate.OPENAI_EMBEDDING_API_KEY or OPENAI_API_KEY is configured in the process environment. This path sends batches of signal-summary or memory text for indexing, plus semantic-search query text—including user text submitted through assistant memory lookup or search—to OPENAI_EMBEDDING_BASE_URL, or to OpenAI's API when no custom base is set. It is independent of the reasoning-location selector. With neither key set, SkyTwin uses its local hash-based embedding fallback and sends neither memory nor query text to an embedding service.:local; Ollama 0.18 or newer rejects remote-backed aliases under that selector, and SkyTwin never retries without it. The configured-provider mode may send prompts and responses over the external network; loopback Ollama is treated as potentially remote in that mode, while the selected endpoint follows its operator's disclosed policy. The separate verified_private_cloud mode currently admits only SkyTwin's pinned TrustedRouter adapter. TrustedRouter requires a fresh same-session gateway attestation plus an exact-byte receipt whose selected upstream tier is tee-verified. NEAR AI is visible as verification-pending but unavailable because its public base-CVM evidence does not pin the dynamically selected model/proxy workload; UI, API, database, and runtime gates reject it. Any failed or stale TrustedRouter verification stops that path without conventional-provider fallback. HTTPS, an API key, a provider name, or a custom URL alone never selects this label. See the confidential inference guide for the exact guarantees and limits.
SKYTWIN_REASONING_MODE value instead of silently crossing locations on fallback.
Separately from the list above, the desktop app can send a PII-scrubbed crash report to crash.skytwin.dev if — and only if — you turn that default-off setting on. The report has no dedicated Google or Microsoft data fields, but its error message or stack could incidentally contain content that pattern-based scrubbing does not recognize; see Telemetry and crash reports for the exact contents and residual risk.
We do not sell user data.
The SkyTwin development team cannot directly access your provider account or the application database stored on your device. If you enable crash reporting, authorized maintainers can read the report fields described above while diagnosing a failure; that error text may contain incidental user content that scrubbing did not recognize. Access to the local database itself is limited to:
The isolated sample receives no information from Google APIs. Any BYO alpha, experimental source, or future managed use must adhere to the Google API Services User Data Policy, including the Limited Use requirements. Specifically:
DELETE /api/users/:userId?confirm=delete-my-data) and underlying purge function (userPurgeRepository.purgeUser in packages/db/src/repositories/user-purge-repository.ts) execute the delete inside a CRDB serializable transaction, so a failure rolls back cleanly. The cascade list is exhaustive — every table backed by a user_id → users(id) foreign key carries ON DELETE CASCADE (see migration 061-cascade-cleanup.sql from #413), and the chained children (e.g. candidate_actions.decision_id, inference_receipts.decision_id, twin_profile_versions.profile_id, execution_plans.decision_id) are deleted explicitly or by their own cascading foreign key. Deleting local data does not revoke a provider-side grant created by an earlier development build; remove that grant through the applicable provider's account controls as well.SkyTwin is not designed for or directed at children under 13. We do not knowingly collect data from children.
Material changes will be announced in the project CHANGELOG on GitHub (CHANGELOG.md) and reflected here. This page is versioned in git alongside the source code; previous revisions are available in the repository history.
Privacy questions, security disclosures, or data-handling concerns: open an issue at github.com/jayzalowitz/skytwin/issues or, for security-sensitive matters, follow the disclosure process described in SECURITY.md.